package flown.window.graphics;


import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import javax.swing.JPanel;

import flown.window.Window;
import flown.window.Dialog;
import flown.window.窗口;
import flown.window.listener.MouseListener;
import flown.window.listener.WindowListener;


/**
 * 场景类
 * */
public class Scene extends JPanel
{
	private BufferedImage image;
	private Renderer2D renderer;///< 渲染器
	private boolean init = false;


	/*场景事件*/
	/**初始化事件*/
	private Event<Renderer2D> init_event = renderer -> {};
	/**场景渲染事件*/
	private Event<Renderer2D> render_event = (renderer) -> {};
	/**场景普通事件*/
	private final ArrayList<Event<Renderer2D>> common_event = new ArrayList<Event<Renderer2D>>();


	public Scene(){ this(0, 0); }
	public Scene(int width, int height)
	{
		this.setBounds(0, 0, width, height);
		this.ChangeImageWH(width, height);
	}
	public Scene(Window w)
	{
		this.setBounds(0, 0, w.GetFrame().getWidth(), w.GetFrame().getHeight());
		this.AddInWindow(w);
	}
	public Scene(窗口 w)
	{
		this.setBounds(0, 0, w.获取窗口().getWidth(), w.获取窗口().getHeight());
		this.AddInWindow(w);
	}
	public Scene(Dialog dialog)
	{
		this.setBounds(0, 0, dialog.GetWidth(), dialog.GetHeight());
		this.AddInWindow(dialog);
	}


	private void ChangeImageWH(int width, int height)
	{
		if (width == 0 || height == 0)
			return;
		System.out.println("TransformImageWidthAndHeight");
		this.image = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
		Graphics2D g2d = this.image.createGraphics();
		if (this.renderer == null)
			this.renderer = new Renderer2D(g2d);
		this.renderer.SetGraphics2D(g2d);
		this.renderer.GetGraphics2D().clearRect(0, 0, this.image.getWidth(), this.image.getHeight());
		this.renderer.SetPaint(Color.WHITE);
	}


	/*
	绘制组件的边框。
	@Override public void paintBorder(Graphics g) {super.paintBorder(g);}

	绘制此组件的子组件。
	@Override public void paintChildren(Graphics g){super.paintChildren(g);}

	如果UI委托为非空，则调用UI委托的绘制方法。
	@Override public void paintComponent(Graphics g)
	{super.paintComponent(g);}

	绘制此组件及其所有子组件。
	@Override public void paintAll(Graphics g){super.paintAll(g);}
	*/

	/**
	 * 由Swing调用以绘制组件。这个方法实际上将绘画工作委托给三个受保护的方法：paintComponent、paintBorder和paintChildren。
	 * @param g Graphics
	 * */
	@Override public void paint(Graphics g)
	{
		super.paint(g);

		if (this.renderer == null)
			this.paint(g);

		this.renderer.GetGraphics2D().clearRect(0, 0, this.image.getWidth(), this.image.getHeight());

		if (!init)
		{
			this.init_event.invoke(this.renderer);
			this.init = true;
		}


		this.render_event.invoke(this.renderer);//渲染事件
		for(Event<Renderer2D> e : this.common_event)
			e.invoke(this.renderer);//执行普通事件
		g.drawImage(this.image, 0, 0, null);


		super.repaint();
	}



	/**
	 * 获取Scene上的Graphics对象
	 * @return Graphics2D
	 */
	public final Graphics2D GetGraphics2D() { return this.renderer.GetGraphics2D(); }


	/**
	 * 设置初始化事件
	 * @param event 初始化事件
	 * */
	public final void SetInitEvent(Event<Renderer2D> event) { this.init_event = event; }


	/**
	 * 设置渲染事件
	 * @param event 渲染事件
	 * */
	public final void SetRenderEvent(Event<Renderer2D> event) { this.render_event = event; }


	/**
	 * 添加普通事件
	 * @param event 普通事件
	 */
	public final int AddCommonEvent(Event<Renderer2D> event)
	{
		this.common_event.add(event);
		return this.common_event.size() - 1;
	}

	/**
	 * 移除普通事件
	 * @param index 索引
	 */
	public final void RemoveCommonEvent(int index)
	{
		this.common_event.remove(index);
	}

	/**
	 * @return return CommonEvent
	 */
	public final ArrayList<Event<Renderer2D>> GetCommonEvent() { return this.common_event; }


	/**
	 * 设置场景使用的渲染器
	 * @param renderer 给场景的渲染器
	 * */
	public final void SetRenderer(Renderer2D renderer) {this.renderer = renderer;}

	/**
	 * 获取场景使用的渲染器
	 * @return Renderer2D
	 * */
	public final Renderer2D GetRenderer() {return this.renderer;}

	/**
	 * 设置鼠标监听器
	 * @param listener 要设置的监听器
	 * */
	public final void SetMouseListener(MouseListener listener)
	{
		this.addMouseListener(listener);
		this.addMouseMotionListener(listener);
		this.addMouseWheelListener(listener);
	}


	/**
	 * 设置key监听器
	 * @param listener 要设置的监听器
	 * */
	public final void SetKeyListener(KeyListener listener){this.addKeyListener(listener);}

	/**
	 * 设置鼠标监听器和key监听器
	 * @param listener 要设置的监听器
	 * */
	public final void SetMouseAndKeyListener(WindowListener listener)
	{
		this.addMouseListener(listener);
		this.addMouseMotionListener(listener);
		this.addMouseWheelListener(listener);
		this.addKeyListener(listener);
	}


	/**
	 * 将场景添加至窗口
	 * @param w 场景要添加到的窗口
	 * */
	public final void AddInWindow(Window w)
	{
		w.GetFrame().add(this);
		w.SetVisible(true);
		this.ChangeImageWH(this.getWidth(), this.getHeight());

		Scene that = this;
		this.addComponentListener(new ComponentListener() {
			@Override
			public void componentResized(ComponentEvent e)
			{
				int w = e.getComponent().getWidth();
				int h = e.getComponent().getHeight();
				System.out.println("SceneWidth:" + w);
				System.out.println("SceneHeight:" + h);
				that.ChangeImageWH(w, h);
			}
			@Override public void componentMoved(ComponentEvent e) {}
			@Override public void componentShown(ComponentEvent e) {}
			@Override public void componentHidden(ComponentEvent e) {}
		});
	}


	/**
	 * 将场景添加至窗口
	 * @param w 场景要添加到的窗口
	 * */
	public final void AddInWindow(窗口 w)
	{
		w.获取窗口().add(this);
		w.设置可视(true);
		this.ChangeImageWH(this.getWidth(), this.getHeight());

		Scene that = this;
		this.addComponentListener(new ComponentListener() {
			@Override
			public void componentResized(ComponentEvent e)
			{
				int w = e.getComponent().getWidth();
				int h = e.getComponent().getHeight();
				System.out.println("SceneWidth:" + w);
				System.out.println("SceneHeight:" + h);
				that.ChangeImageWH(w, h);
			}
			@Override public void componentMoved(ComponentEvent e) {}
			@Override public void componentShown(ComponentEvent e) {}
			@Override public void componentHidden(ComponentEvent e) {}
		});
	}


	/**
	 * 将场景添加至窗口
	 * @param dialog 场景要添加到的窗口
	 * */
	public final void AddInWindow(Dialog dialog)
	{
		dialog.Add(this);
		dialog.SetVisible(true);
		this.ChangeImageWH(this.getWidth(), this.getHeight());

		Scene that = this;
		this.addComponentListener(new ComponentListener() {
			@Override
			public void componentResized(ComponentEvent e)
			{
				int w = e.getComponent().getWidth();
				int h = e.getComponent().getHeight();
				System.out.println("SceneWidth:" + w);
				System.out.println("SceneHeight:" + h);
				that.ChangeImageWH(w, h);
			}
			@Override public void componentMoved(ComponentEvent e) {}
			@Override public void componentShown(ComponentEvent e) {}
			@Override public void componentHidden(ComponentEvent e) {}
		});
	}

}











